#ifndef HARMONY_SEARCH_
#define HARMONY_SEARCH_

#include "SysState.h"

#include <stdlib.h>
#include <cstdlib>
#include <vector>
using namespace std;

// One possible termination condition for Harmony search.
const int NUM_ITERATIONS = 100;

// Determines if vector vec contains all false's.
bool isAllZeros(const vector<bool>& vec);

// Gets execution time based on one solution and current sysstate.
double getExecTime(const SysState& sysstate, const vector<bool>& soln);

// Compare function for sorting harmony memory in terms of obj_hybrid_pwt values.
// First element of a pair is obj_hybrid_pwt, Second element of a pair is index in the original hmem.
bool compare_function(pair<double, int> s1, pair<double, int> s2);

class HarmonySearch {
  public:
    HarmonySearch(int hms, double hmcr, double par, double alpha, double beta, int n, const SysState& sysstate);
    ~HarmonySearch();
    vector<bool> runHarmonySearch();

  private:
    friend class TestHarmonySearch;

    int HMS;  // Harmony memory size.
    double HMCR;  // Harmony memory considerating rate.
    double PAR;  // Pitch adjustment rate.
    double ALPHA;  // Combination parameter for hybrid objective function.
    double BETA;  // Parameter for constraint.
    int n;  // Number of dimensions for each solution.
    const SysState& sys_state;

    // Harmony memory.
    vector<vector<bool> > hmem;

    void initHarmonyMemory();
    bool satisfyConstraint(const vector<bool>& soln);

    double getD1(const vector<bool>& soln);
    double getD2(const vector<bool>& soln);
    double getD3(const vector<bool>& soln);
    double getExpr1(const vector<bool>& soln, int i);
    double getExpr2(const vector<bool>& soln, int i, int j);

    vector<bool> generateOneNewSoln();
    void sortHarmonyMemory();
    bool isInHarmonyMem(const vector<bool>& vec);

    double obj_avg_pwt(const vector<bool>& soln);
    double obj_max_pwt(const vector<bool>& soln);
    double obj_hybrid_pwt(const vector<bool>& soln);
};

#endif  // HARMONY_SEARCH_
